#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2023/3/21 18:50
# @Author  : huidong.bai
# @File    : run_test.py
# @Software: PyCharm
# @Mail    : MasterBai2018@outlook.com
import configparser
import pdb
import shutil
import signal
import sys
import os
import json
import time
import datetime
import subprocess
import multiprocessing
from multiprocessing import Process
from multiprocessing import Lock
from src.utils.DockerIntegrated import MangoDocker
from src.userInterface.parse_config import Parse, ConcurrentCtr
from src.userInterface.deploy_environment import resource_deploy, get_work_mode
from src.userInterface.process_result import merge_result, process_valgrind_info, generate_report
from conf.MongoConfig import AvailableSuite
from src.utils.file_reader import FileReader
from src.utils.MangoDownload import Download, FileType
from src.utils.DownloadLibrary import DownloadLibrary
from src.utils.send_wechat import SendMessage

multiprocessing.set_start_method("fork")

tools = ["src/testsuite"]
parse_solution = []
detail_version = False
ftp_downloader = None
library_downloader = None
log_save_option = None
docker_image = None
check_project = None
container_ids = []
message = SendMessage()


class SuiteProcessArg:
    rootDir = None
    workMode = None
    tools = None
    processCounter = None
    processMutex = None
    fileRow = None

    def __init__(self, rootDir, workMode, tools, processCounter, processMutex, fileRow):
        self.rootDir = rootDir
        self.workMode = workMode
        self.tools = tools
        self.processCounter = processCounter
        self.processMutex = processMutex
        self.fileRow = fileRow


class AtomicSuite:
    suiteID = -1
    suiteName = None
    suiteTag = None
    suiteConf = None
    suiteCaseList = None
    suiteAbstract = None

    scenarioID = -1
    scenarioName = None
    scenarioConf = None

    solutionID = -1
    solutionName = None

    stdoutFile = None
    useValgrind = None
    repeatNum = 1

    nluRes = None
    project = None
    ctr = None

    workspace = None

    def __init__(self, suiteID, suiteName, suiteTag, suiteConf, suiteCaseList, suiteAbstract):
        self.__reset()
        self.suiteID = suiteID
        self.suiteName = suiteName
        self.suiteTag = suiteTag
        self.suiteConf = suiteConf
        self.suiteCaseList = suiteCaseList
        self.suiteAbstract = suiteAbstract

    def __reset(self):
        self.suiteID = -1
        self.suiteName = None
        self.suiteTag = None
        self.suiteConf = None
        self.suiteCaseList = None
        self.suiteAbstract = None

        self.scenarionID = -1
        self.scenarioName = None
        self.scenarionConf = None

        self.solutionID = -1
        self.solutionName = None

        self.stdoutFile = None
        self.useValgrind = None
        self.repeatNum = 1

        self.ctr = None

    def setScenarioInfo(self, scenarioID, scenarioName, scenarioConf):
        self.scenarioID = scenarioID
        self.scenarioName = scenarioName
        self.scenarioConf = scenarioConf

    def setStdoutFile(self, stdoutFile):
        self.stdoutFile = stdoutFile

    def setUseValgrind(self, useValgrind):
        self.useValgrind = useValgrind

    def setRepeatNum(self, num):
        self.repeatNum = num

    def setConcurrentCtr(self, info):
        self.ctr = info

    def setSolutionInfo(self, solutionID, solutionName):
        self.solutionID = solutionID
        self.solutionName = solutionName

    def setWorkspace(self, workspace):
        self.workspace = workspace

    def setNluRes(self, nluRes):
        self.nluRes = nluRes

    def setproject(self, project):
        self.project = project


def generate_suites_list():
    from conf.MongoConfig import AvailableSuite
    for tool in AvailableSuite:
        print(f"{tool.name}:\n\t{tool.summary}")
    return


def saveCrashInfo(suite, suite_id, suite_tag, config, suite_case_list, scene, scenario_config, reportNameRe):
    result = {'suiteName': suite, 'suiteID': suite_id, 'suiteTag': suite_tag, 'suiteConfig': config,
              'suiteCaseList': suite_case_list, 'suiteAbstract': "no result, maybe the current suite execution crashed"}

    result_summary = {'totalTime': 0, 'caseNum': 0, 'failedNum': 0, 'S': 0, 'A': 0, 'B': 0, 'C': 0, 'passed': "no"}
    result['summary'] = result_summary

    result_caseInfo = []
    result['caseInfo'] = result_caseInfo

    with open(reportNameRe, 'w') as fp:
        _result = json.dumps(result, ensure_ascii=False)
        fp.write(_result)


def run_per_suite(process_id, root_dir, work_mode, suite_id, suite, suite_tag, suite_abstract, config,
                  suite_case_list, scene,
                  scenario_config, workspace, case_line, nlu_res, project, stdoutFile=None, useValgrind=False,
                  generate_case=None,
                  update_resource_path=None):
    # pdb.set_trace()
    if suite not in AvailableSuite.__members__:
        return 'ERROR'

    suite_dir = os.path.join(workspace, scene, str(suite_id))
    if not os.path.exists(suite_dir):
        os.makedirs(suite_dir)

    source = AvailableSuite[suite].value

    tool_name = os.path.basename(source)
    destination = os.path.join(suite_dir, tool_name)
    # shutil.copy(source, destination)
    # TODO 测试一下
    destination = source

    global detail_version
    if detail_version:
        tool = "python3 -m pytest -r sfE --color=yes -vs " + destination + " --mongo_detail=True"
    else:
        tool = "python3 -m pytest -r sfE --tb=no --color=yes -vs " + destination

    global ftp_downloader
    if ftp_downloader in [0, 1, 2]:
        tool += f" --mongo_ftp_downloader={ftp_downloader}"

    global log_save_option
    if log_save_option:
        tool += f" --mongo_log_save_option=True"

    if "GDB" in work_mode:
        tool += " --gdb_mode=True"

    cfgFile = " --mongo_config=" + config

    updResPath = ""
    if update_resource_path is not None:
        updResPath = " --mongo_update_common_resource=" + workspace + update_resource_path

    reportName = "%s/%s:%d_report_%s" % (workspace, scene, suite_id, suite)
    reportNameRe = reportName.replace(':', '/')

    report = " --mongo_report=" + reportName
    mongo_root_dir = " --mongo_root_dir=" + root_dir
    mongo_work_space = " --mongo_workspace=" + workspace + '/' + scene

    suiteID = " --mongo_suite_id=" + "%d" % suite_id
    suiteName = " --mongo_suite_name=%s" % suite

    suiteTag = ""
    if suite_tag is not None:
        suiteTag = " --mongo_suite_tag=" + suite_tag

    caseList = ""
    if suite_case_list is not None:
        caseList = " --mongo_case_list=" + suite_case_list

    abstract = ""
    if suite_abstract is not None:
        abstract = " --mongo_suite_abstract=" + suite_abstract

    generateCase = ""
    if generate_case is not None:
        generateCase = " --mongo_generate_case=" + generate_case

    caseLine = ""
    if case_line is not None:
        caseLine = " --mongo_filter_case_line=" + case_line

    scenaroConf = ""
    if scenario_config is not None:
        scenaroConf = " --mongo_scenario_config=" + scenario_config

    nluRes = ""
    if nlu_res is not None:
        nluRes = " --mongo_nlu_res=" + nlu_res

    isProject = " --mongo_check_project=" + project

    solutionSpace = " --mongo_solution_space=" + workspace

    # allure测试数据路径
    allure_result = os.path.join(workspace, "allure_result")
    if not os.path.exists(allure_result):
        os.makedirs(allure_result)
    
    allure_attach_path = os.path.join(workspace, "allure_attach")
    if not os.path.exists(allure_attach_path):
        os.makedirs(allure_attach_path)

    allure_cmd = f" --alluredir={allure_result}"
    no_stacktrace = " --allure-no-capture"

    command = tool + suiteID + suiteName + suiteTag + cfgFile + caseList + abstract + caseLine + scenaroConf + \
              report + mongo_root_dir + mongo_work_space + generateCase + nluRes + updResPath + solutionSpace + allure_cmd + no_stacktrace + isProject
    if stdoutFile:
        printLog = " | tee -a " + stdoutFile
        command = command + printLog

    if useValgrind is False:
        print("start to run suite:%s" % suite)
        print("======================")
        print(command)
        print("======================")
        if docker_image != "no":
            docker = MangoDocker(image=docker_image, workspace="/mango")
            # 设置docker挂载指令
            docker.mount(f"{os.getcwd()}:/mango",
                         './TestAudio:/mango/TestAudio', './TestCase:/mango/TestCase',
                         './TestResource:/mango/TestResource')
            ret = docker.start()
            if ret != 0:
                print(f"Docker容器启动失败:{ret}")
                docker.free()
                return None
            ret = docker.excute(command)
            if ret != 0:
                print(f"PYTEST执行失败:{ret}")
                docker.free()
                return None
            docker.free()

        else:
            result = subprocess.call(command, shell=True)
            if -11 == result:
                print("Execution case[%s] crashed" % suite)
            # sys.exit(0)
        # reportName = reportName.replace(':', '/')
        if os.path.isfile(reportNameRe):
            return reportNameRe
        else:
            saveCrashInfo(suite, suite_id, suite_tag, config, suite_case_list, scene, scenario_config, reportNameRe)
            return reportNameRe
    else:
        valgrindInfo = "%s/%s/valgrind_%s" % (workspace, scene, suite)
        valgrindReport = "%s/%s/report_valgrind_%s" % (workspace, scene, suite)
        _command = "valgrind --log-file=%s --leak-check=full --track-origins=yes " % valgrindInfo + command
        print("======================")
        print(command)
        print("======================")
        result = subprocess.call(_command, shell=True)
        if -11 == result:
            print("Execution case[%s] crashed" % suite)
            sys.exit(0)
        ret = process_valgrind_info(valgrindInfo, valgrindReport, suite)
        if ret is True:
            return valgrindReport
        else:
            return None


def report_file_manager(report_dir, suite_name):
    substr = "report_%s" % suite_name
    filelist = os.listdir(report_dir)
    # print("report list>")
    # print(filelist)
    # print("<<<<<")
    match_num = 0
    for f in filelist:
        if f.find(substr) != -1:
            match_num += 1
    return "%s:%s_%d" % (report_dir, substr, match_num)


class MultiProcess(Process):
    def __init__(self, concurrentCtr, atomicSuitesPool, suiteProArg, log, updResPath):
        super(MultiProcess, self).__init__()
        self.pidCtr = concurrentCtr
        self.suiteProArg = suiteProArg
        self.mutex = suiteProArg.processMutex
        self.atomicSuitesPool = atomicSuitesPool
        self.total_suite_num = len(atomicSuitesPool)
        self.logFile = open(log, 'a')
        self.updResPath = updResPath

    def getSuite(self):
        if self.pidCtr.pid < self.pidCtr.cpNum:
            for suite in self.atomicSuitesPool:
                if suite.solutionID * 10000 + suite.scenarioID * 1000 + suite.suiteID in self.suiteProArg.processCounter:
                    continue
                else:
                    if suite.suiteTag is not None and 'CP' in suite.suiteTag:
                        return suite
                    else:
                        continue
            for suite in self.atomicSuitesPool:
                if suite.solutionID * 10000 + suite.scenarioID * 1000 + suite.suiteID in self.suiteProArg.processCounter:
                    continue
                else:
                    if (self.pidCtr.onlineNum <= 0) or (suite.suiteTag is not None and 'ONLINE' not in suite.suiteTag):
                        return suite
                    else:
                        continue
            return None
        elif self.pidCtr.pid < self.pidCtr.onlineNum + self.pidCtr.cpNum:
            for suite in self.atomicSuitesPool:
                if suite.solutionID * 10000 + suite.scenarioID * 1000 + suite.suiteID in self.suiteProArg.processCounter:
                    continue
                else:
                    if suite.suiteTag is not None and 'ONLINE' in suite.suiteTag and 'CP' not in suite.suiteTag:
                        return suite
                    else:
                        continue
            for suite in self.atomicSuitesPool:
                if suite.solutionID * 10000 + suite.scenarioID * 1000 + suite.suiteID in self.suiteProArg.processCounter:
                    continue
                else:
                    if (self.pidCtr.cpNum <= 0) or (suite.suiteTag is not None and 'CP' not in suite.suiteTag):
                        return suite
                    else:
                        continue
            return None
        else:
            # the other process match the suite that neigther 'CP' nor 'ONLINE'
            for suite in self.atomicSuitesPool:
                if suite.solutionID * 10000 + suite.scenarioID * 1000 + suite.suiteID in self.suiteProArg.processCounter:
                    continue
                else:
                    if (suite.suiteTag is not None and 'ONLINE' in suite.suiteTag and self.pidCtr.onlineNum > 0) or \
                            (suite.suiteTag is not None and 'CP' in suite.suiteTag and self.pidCtr.cpNum > 0):
                        continue
                    else:
                        return suite
            return None

    def run(self):
        # while(self.suite_count.value < self.total_suite_num):
        while True:
            if self.pidCtr.pid == 0:
                time.sleep(1)
            self.mutex.acquire()

            runNum = 0
            for counter in self.suiteProArg.processCounter:
                if counter > 0:
                    runNum += 1

            if runNum >= self.total_suite_num:
                self.logFile.write(
                    "%s PID:%d state:over\n" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), self.pidCtr.pid))
                self.mutex.release()
                break

            suite = self.getSuite()

            if suite is None:
                self.logFile.write(
                    "%s PID:%d state:over\n" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), self.pidCtr.pid))
                self.mutex.release()
                break

            self.suiteProArg.processCounter[runNum] = suite.solutionID * 10000 + suite.scenarioID * 1000 + suite.suiteID

            self.logFile.write("%s PID:%d state:start solution:%s scenario:%s suite:%s  tag:%s sum:%d_%d_%d\n" %
                               (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), self.pidCtr.pid,
                                suite.solutionName, suite.scenarioName,
                                suite.suiteName, suite.suiteTag, suite.solutionID, suite.scenarioID, suite.suiteID))
            self.logFile.flush()
            self.mutex.release()

            start_time = time.time()
            stdoutFile = None
            if suite.stdoutFile is not None:
                stdoutFile = "%s_suiteID_%d" % (suite.stdoutFile, suite.suiteID)
            print("total_suite_num:%d-%d, runNum:%d" % (
                self.total_suite_num, len(self.suiteProArg.processCounter), runNum + 1))
            print("process id:%d suite:%d-%s-%s stdoutFile:%s" % (
                self.pidCtr.pid, suite.suiteID, suite.suiteName, suite.suiteTag, stdoutFile))
            for i in range(0, suite.repeatNum):
                # run case
                res = run_per_suite(self.pidCtr.pid, self.suiteProArg.rootDir, self.suiteProArg.workMode, suite.suiteID,
                                    suite.suiteName, suite.suiteTag, suite.suiteAbstract, suite.suiteConf,
                                    suite.suiteCaseList, suite.scenarioName,
                                    suite.scenarioConf, suite.workspace,
                                    self.suiteProArg.fileRow,
                                    suite.nluRes, suite.project, stdoutFile, suite.useValgrind, None, self.updResPath)

                if res is None:
                    print("The suite[%s] didn't generate report" % suite.suiteName)
                elif res == 'ERROR':
                    print('The suite[%s] and config[%s] do not match.' % (suite.suiteName, suite.suiteConf))
                else:
                    pass
            end_time = time.time()
            self.mutex.acquire()
            end_time = time.time()
            self.logFile.write("%s PID:%d state:end solution:%s scenario:%s suite:%s  tag:%s sum:%d_%d_%d\n" %
                               (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), self.pidCtr.pid,
                                suite.solutionName, suite.scenarioName,
                                suite.suiteName, suite.suiteTag, suite.solutionID, suite.scenarioID, suite.suiteID))
            self.logFile.flush()
            self.mutex.release()
        self.logFile.close()


def saveResult(solution, mongo_work_space):
    with open("%s/solution.json" % mongo_work_space, 'w') as fp:
        result = json.dumps(solution, ensure_ascii=False)
        fp.write(result)


def resuce_report(tester_args, times):
    # pdb.set_trace()
    mongo_solution = tester_args.mongo_solution
    mongo_work_space = tester_args.mongo_work_space
    parses = []
    solutions = []

    # 支持 -c solution1-solution2-solution3 跑多个solution
    for solution_config in mongo_solution.split('-'):
        solution_filename = os.path.splitext(os.path.basename(solution_config))[0]
        tester_args.mongo_work_space = os.path.join(mongo_work_space, solution_filename)

        report_data = []
        parse = Parse(solution_config, tester_args.mongo_tag, tester_args.mongo_enable,
                      tester_args.mongo_work_space)
        parses.append(parse)
        tasks = parse.get_tasks()
        enable = parse.get_enable()
        print("enable:", enable)
        disable = parse.get_disable()
        mongoConfig = parse.get_mongoConfig()
        emailOption = mongoConfig.get_emailOption()
        for scenario in tasks:
            if "ALL" in disable:
                break
            if scenario.name in disable:
                continue
            if scenario.name not in enable and "ALL" not in enable:
                continue
            sceneResult = {}
            sceneResult['sceneName'] = scenario.name
            sceneResult['owner'] = scenario.owner
            sceneResult['sceneInfo'] = {}
            sceneResult['sceneInfo']['suiteSummary'] = {}
            sceneResult['sceneInfo']['suiteSummary']['suiteNum'] = 0
            sceneResult['sceneInfo']['suiteSummary']['passedNum'] = 0
            sceneResult['sceneInfo']['suiteSummary']['caseNum'] = 0
            sceneResult['sceneInfo']['suiteSummary']['totalTime'] = 0
            sceneResult['sceneInfo']['suiteSummary']['failedNum'] = 0
            sceneResult['sceneInfo']['suiteSummary']['S'] = 0
            sceneResult['sceneInfo']['suiteSummary']['A'] = 0
            sceneResult['sceneInfo']['suiteSummary']['B'] = 0
            sceneResult['sceneInfo']['suiteSummary']['C'] = 0
            sceneResult['sceneInfo']['suiteInfo'] = []

            report_dir = "%s/%s" % (tester_args.mongo_work_space, scenario.name)
            if os.path.exists(report_dir) is False:
                continue
            file_list = os.listdir(report_dir)
            for f in file_list:
                if "_report_" not in f:
                    continue
                report = "%s/%s" % (report_dir, f)
                merge_result(report, sceneResult['sceneInfo']['suiteInfo'], sceneResult['sceneInfo']['suiteSummary'])
            report_data.append(sceneResult)

        print("Begin to generate report....")
        times['end'] = time.time()
        data = generate_report(tester_args.mongo_work_space, tester_args.mongo_report, report_data, parse, times)
        print("Generate report complete....\n")

        solution = {'solution_name': solution_config.split('/')[-1], 'solution_report': data}
        solutions.append(solution)
    tester_args.mongo_work_space = mongo_work_space

    return solutions

def get_Resource_Info(config):
    config_reader = FileReader(config)
    lcs_config = config_reader.get_config("LCS_DECODER_PATH")
    info = ''
    if lcs_config:
        lcs_config_reader = FileReader(lcs_config)
        lcs_resource = lcs_config_reader.get_config("LCS_RES_PATH")
        version = os.path.join(lcs_resource, 'VERSION')
        if os.path.exists(version):
            with open(version,mode='r') as f:
                for i in f.readlines():
                    if 'VERSION' in i: 
                        info += f'TSAP_{i}'
                        break
                    else: continue
    return info
        

def run_all_test(tester_args, root_dir):
    times = {'start_time': datetime.datetime.now(), 'start': time.time()}
    if tester_args.mongo_rescue:
        resuce_report(tester_args, times)
        sys.exit(0)

    global detail_version
    detail_version = True if tester_args.mongo_detail_version else False

    global ftp_downloader
    ftp_downloader = tester_args.mongo_ftp_downloader

    global library_downloader
    library_downloader = True if tester_args.mongo_library_downloader else False

    global log_save_option
    log_save_option = True if tester_args.mongo_log_save_option == "yes" else False

    global docker_image
    docker_image = tester_args.mongo_docker_option

    global check_project
    check_project = tester_args.mongo_check_project
    project_config = configparser.ConfigParser()
    project_config.read('conf/project.ini')
    project_all_list = project_config.sections()
    if check_project not in project_all_list:
        print(f" the selected {check_project} is not supported ")
        print(project_all_list)
        sys.exit(0)

    # 自动下载动态库
    if library_downloader:
        try:
            libraryDown = DownloadLibrary(check_project)
            libraryDown.run_down(tester_args.mongo_library_downloader)
        except Exception as e:
            print(f"Download lib fail, error:{e}")
            sys.exit(0)

    # 列出当前支持的Suite列表
    if tester_args.mongo_list_suites:
        generate_suites_list()
        sys.exit(0)
    work_mode = get_work_mode(tester_args)

    parse = None

    if work_mode == "FILTER" or work_mode == "GDB_FILTER":
        solutions = []
        report_data = []
        solution = {'solution_name': "FILTER", 'solution_report': report_data}
        solutions.append(solution)
        sceneResult = {'sceneName': 'FILTER', 'sceneInfo': {}}
        sceneResult['sceneInfo']['suiteInfo'] = []
        sceneResult['sceneInfo']['suiteSummary'] = {}
        sceneResult['sceneInfo']['suiteSummary']['suiteNum'] = 0
        sceneResult['sceneInfo']['suiteSummary']['passedNum'] = 0
        sceneResult['sceneInfo']['suiteSummary']['caseNum'] = 0
        sceneResult['sceneInfo']['suiteSummary']['totalTime'] = 0
        sceneResult['sceneInfo']['suiteSummary']['failedNum'] = 0
        sceneResult['sceneInfo']['suiteSummary']['S'] = 0
        sceneResult['sceneInfo']['suiteSummary']['A'] = 0
        sceneResult['sceneInfo']['suiteSummary']['B'] = 0
        sceneResult['sceneInfo']['suiteSummary']['C'] = 0

        tester_args.mongo_work_space = os.path.join(tester_args.mongo_work_space, tester_args.mongo_dependent_resources)

        if os.path.exists(tester_args.mongo_work_space):
            shutil.rmtree(tester_args.mongo_work_space)
        os.makedirs(tester_args.mongo_work_space)

        # 资源自动下载资源
        if ftp_downloader == 0 or ftp_downloader == 2:
            downloader = Download()
            config_reader = FileReader(tester_args.mongo_filter_config)
            lcs_config = config_reader.get_config("LCS_DECODER_PATH")
            downloader.start_download(lcs_config, FileType.FILE_TYPE_CONFIG)
            downloader.start_download(tester_args.mongo_filter_config, FileType.FILE_TYPE_CONFIG)

        result = run_per_suite(-1, root_dir, work_mode, 1, tester_args.mongo_filter, None, None,
                               tester_args.mongo_filter_config,
                               tester_args.mongo_case, "FILTER", tester_args.mongo_project,
                               tester_args.mongo_work_space,
                               tester_args.mongo_filter_case_line, None, tester_args.mongo_check_project, None,
                               False, tester_args.mongo_generate_case)
        if result is None:
            print("The suite[%s] didn't generate report" % tester_args.mongo_filter)
        elif result == 'ERROR':
            print('The suite[%s] and config[%s] do not match.' % (
                tester_args.mongo_filter, tester_args.mongo_filter_config))
        else:
            merge_result(result, sceneResult['sceneInfo']['suiteInfo'], sceneResult['sceneInfo']['suiteSummary'])
            report_data.append(sceneResult)

        print("Begin to generate report....")
        times['end'] = time.time()
        generate_report(tester_args.mongo_work_space, tester_args.mongo_report, report_data, parse, times)
        print("Generate report complete....\n")
        return
    else:
        mongo_solution = tester_args.mongo_solution
        mongo_work_space = tester_args.mongo_work_space
        atomicSuitesPool = []
        solutionsNum = len(mongo_solution.split('-'))
        solutionID = 0
        solutionName = None
        updResPath = None

        global_decoder_config = None
        global_lcs_config = None

        for solution_config in mongo_solution.split('-'):
            solutionID += 1
            solutionName = solution_config.split('/')[-1]
            # pdb.set_trace()
            times['start_time'] = datetime.datetime.now()
            times['start'] = time.time()
            tester_args.mongo_solution = solution_config
            tester_args.mongo_work_space = os.path.join(mongo_work_space, solutionName)
            print(tester_args.mongo_work_space)
            print("Begin to parse the solution file....")
            parse = Parse(solution_config, tester_args.mongo_tag, tester_args.mongo_enable, tester_args.mongo_work_space)

            tasks = parse.get_tasks()
            enable = parse.get_enable()
            disable = parse.get_disable()
            user = parse.get_user()
            need_clean_workspace = parse.get_needCleanWorkSpace()

            if os.path.exists(tester_args.mongo_work_space):
                shutil.rmtree(tester_args.mongo_work_space, ignore_errors=True)
            os.makedirs(tester_args.mongo_work_space)

            for scenario in tasks:
                if "ALL" in disable:
                    break
                if scenario.name in disable:
                    continue
                if scenario.name not in enable and "ALL" not in enable:
                    continue
                
                report_dir = os.path.join(tester_args.mongo_work_space, scenario.name)
                if not os.path.exists(report_dir):
                    os.makedirs(report_dir)

                stdoutFile = ''
                if scenario.stdoutFile:
                    subdir = scenario.stdoutFile.split('/')
                    length = len(subdir)
                    if length > 0:
                        stdoutFile = tester_args.mongo_work_space + '/' + scenario.name
                    for i in range(0, length - 1):
                        stdoutFile += '/' + subdir[i]
                    if not os.path.exists(stdoutFile):
                        os.makedirs(stdoutFile)

                    if subdir[-1] is not None:
                        stdoutFile += '/' + subdir[-1]
                    else:
                        stdoutFile += '/log'
                else:
                    stdoutFile = tester_args.mongo_work_space + '/' + scenario.name + '/log'

                for suite in scenario.suiteInfo:
                    global_decoder_config = suite.conf
                    if None is suite:
                        continue

                    # 如果指令中存在-p指令，则覆盖solution中的配置文件
                    if tester_args.mongo_project:
                        suite.set_scenarioConfig(tester_args.mongo_project)
                    global_lcs_config = suite.scenario_conf

                    atomic_suite = AtomicSuite(suite.suiteID, suite.name, suite.tag, suite.conf, suite.caseList, suite.abstract)
                    atomic_suite.setWorkspace(tester_args.mongo_work_space)
                    atomic_suite.setScenarioInfo(scenario.scenarioID, scenario.name, suite.scenario_conf)
                    atomic_suite.setSolutionInfo(solutionID, solutionName)
                    atomic_suite.setStdoutFile(stdoutFile)
                    atomic_suite.setUseValgrind(scenario.useValgrind)
                    atomic_suite.setRepeatNum(scenario.repeatNum)
                    atomic_suite.setConcurrentCtr(parse.get_concurrentCtr(0))
                    atomic_suite.setNluRes(None)
                    atomic_suite.setproject(tester_args.mongo_check_project)
                    atomicSuitesPool.append(atomic_suite)

        # 资源自动下载资源
        if ftp_downloader == 0 or ftp_downloader == 2:
            downloader = Download()
            downloader.start_download(global_lcs_config, FileType.FILE_TYPE_CONFIG)
            downloader.start_download(global_decoder_config, FileType.FILE_TYPE_CONFIG)

        # pdb.set_trace()
        mutex = Lock()
        processCounter = multiprocessing.Array('i', range(len(atomicSuitesPool)))
        for i in range(0, len(atomicSuitesPool)):
            processCounter[i] = 0
        suiteProArg = SuiteProcessArg(root_dir, work_mode, tools, processCounter, mutex, tester_args.mongo_filter_case_line)

        concurrentAtomicSuitesPool = []
        serialAtomicSuitesPool = []
        cpProNum = 0
        onlineProNum = 0
        othersProNum = 0
        for sub_atomic_suite in atomicSuitesPool:
            print(sub_atomic_suite.solutionID, sub_atomic_suite.scenarioID, sub_atomic_suite.suiteID)
            if sub_atomic_suite.ctr.totalProNum == 0:
                serialAtomicSuitesPool.append(sub_atomic_suite)
                continue
            if sub_atomic_suite.ctr.cpNum > cpProNum:
                cpProNum = sub_atomic_suite.ctr.cpNum
            if sub_atomic_suite.ctr.onlineNum > onlineProNum:
                onlineProNum = sub_atomic_suite.ctr.onlineNum
            if sub_atomic_suite.ctr.othersNum > othersProNum:
                othersProNum = sub_atomic_suite.ctr.othersNum
            concurrentAtomicSuitesPool.append(sub_atomic_suite)
        processNum = cpProNum + onlineProNum + othersProNum

        # pdb.set_trace()
        log = "%s/Mongo.log" % mongo_work_space
        logFile = open(log, 'w')
        logFile.write("%s Running process num:%d\tcpNum:%d\tonlineNum:%d\tothersNum:%d\nTotal suiteNum:%d\n" % \
                      (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), processNum, cpProNum, onlineProNum, \
                       othersProNum, len(concurrentAtomicSuitesPool)))
        logFile.close()
        if len(concurrentAtomicSuitesPool) > 0 and processNum > 0:
            processList = []
            for i in range(0, processNum):
                concurrentCtr = ConcurrentCtr(i, None)
                concurrentCtr.updateInfo(i, cpProNum, onlineProNum, othersProNum)
                processList.append(
                    MultiProcess(concurrentCtr, concurrentAtomicSuitesPool, suiteProArg, log, updResPath))

            for p in processList:
                p.start()

            for p in processList:
                p.join()

            for tool in tools:
                for i in range(0, processNum):
                    new_tool = "%s/%s_t%d" % (tester_args.mongo_work_space, tool, i)
                    print("tool path %s" % new_tool)
                    if os.path.exists(new_tool) is True:
                        command = "rm %s" % new_tool
                        print(command)
                        subprocess.call(command, shell=True)

        for suite in serialAtomicSuitesPool:
            for i in range(0, suite.repeatNum):
                result = run_per_suite(-1, suiteProArg.rootDir, suiteProArg.workMode, suite.suiteID,
                                       suite.suiteName, suite.suiteTag, suite.suiteAbstract, suite.suiteConf,
                                       suite.suiteCaseList, suite.scenarioName, suite.scenarioConf, suite.workspace,
                                       suiteProArg.fileRow, suite.nluRes, tester_args.mongo_check_project, suite.stdoutFile, suite.useValgrind, None,
                                       updResPath)
                if result is None:
                    print("The suite[%s] didn't generate report" % suite.suiteName)
                elif result == 'ERROR':
                    print('The suite[%s] and config[%s] do not match.' % (suite.suiteName, suite.suiteConf))
                else:
                    pass

        tester_args.mongo_work_space = mongo_work_space
        tester_args.mongo_solution = mongo_solution

    solutions = resuce_report(tester_args, times)
    saveResult(solutions, tester_args.mongo_work_space)
    generate_allure_report(tester_args)


def generate_allure_report(tester_args):
    try:
        aibs_version, lcs_version = None, None
        if tester_args.mongo_library_downloader:
            aibs_version, lcs_version = tester_args.mongo_library_downloader.split('-')

        solutions = tester_args.mongo_solution
        for solution in solutions.split("-"):
            solution_name = solution.split("/")[-1]
            solution_path = os.path.join(tester_args.mongo_work_space, solution_name)
            allure_report_path = os.path.join(solution_path, 'allure_report')
            allure_result_path = os.path.join(solution_path, 'allure_result')
            environment_config = os.path.join(allure_result_path, "environment.properties")
            with open(environment_config, mode='w+') as f:
                f.write('SystemVersion: linux-x86\n')
                f.write(f"SolutionFile: {solution}\n")
                f.write(f"AibsVersion : {aibs_version}\n")
                f.write(f"LCSVersion  : {lcs_version}\n")

            print(f"Begin to generate allure report: {solution_path} start....")
            allure_cmd = ['allure', 'generate', allure_result_path, '-o', allure_report_path]
            subprocess.run(allure_cmd)
            print(f"Generate allure report:{solution_path} complete....\n")

            print(f"Run command:\nallure open {allure_report_path} -p 8889")
            print(f"See the online report:\n\thttp://10.54.1.15:8889")

            if tester_args.mongo_message_wechat:
                # 发送企业微信通知
                message.run_start(solution_path, aibs_version, lcs_version)
    except Exception as e:
        print("generate report error: ", e)
